package org.hsc.httpProxy;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;

import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ServerHandler extends IoHandlerAdapter{
	private static final String encoding = "ISO-8859-1";  
	private static final Logger logger=LoggerFactory.getLogger(ServerHandler.class);
    @Override
    public void exceptionCaught( IoSession session, Throwable cause ) throws Exception
    {
    	 logger.error(cause.getMessage(),cause);
    }
    
    @Override
    public void messageReceived( IoSession session, Object msg ) throws IOException {
    	if(msg==null){
    		return ;
    	}
    	ProxyBean bean=(ProxyBean)msg;
        logger.info("开始转发请求。"+bean.getHost()+":"+bean.getPost());
        
        Socket socket = new Socket(bean.getHost(), bean.getPost());
        socket.setSoTimeout(3000);
        socket.setTcpNoDelay(true);
        socket.setKeepAlive(true);
        	
        OutputStream sout= socket.getOutputStream();
        sout.write(bean.getData().getBytes());
        sout.flush();
        logger.info("转发数据写入完成 ！");
        
        
        InputStream sin=socket.getInputStream();
        
//		StringBuilder sb = new StringBuilder();  
		IoBuffer sb = IoBuffer.allocate(1000).setAutoExpand(true);
		String line; int contentLength = 0;//服务器发送回来的消息长度  
        // 读取所有服务器发送过来的请求参数头部信息  
        String contentEncoding=encoding;
        do {  
        	byte[] bts = readLine(sin, 0);  
        	line=new String(bts,Charset.forName("utf-8"));
        	logger.info("接收到数据:"+line);
            //如果有Content-Length消息头时取出  
            if (line.startsWith("Content-Length")) {  
                contentLength = Integer.parseInt(line.split(":")[1].trim());  
                logger.info("contentLength:"+contentLength);
//            }else if(line.startsWith("Content-Type")){
//            	contentEncoding=
            }
            //打印请求部信息  
            sb.put(bts);  
            //如果遇到了一个单独的回车换行，则表示请求头结束  
        } while (!"".equals(line.trim()));  

        //--输消息的体  
        logger.info("开始读取Body，长度："+contentLength);
        sb.put(readLine(sin, contentLength));  
        
        sb.flip();
		logger.info("开始发送数据:"+new String(sb.array(),encoding));
		
		//buffer.reset();
        session.write(sb);

        sout.close();
        sin.close();
        socket.close();
        logger.warn("Message written...");
    }
    
    /* 
     * 这里我们自己模拟读取一行，因为如果使用API中的BufferedReader时，它是读取到一个回车换行后 
     * 才返回，否则如果没有读取，则一直阻塞，直接服务器超时自动关闭为止，如果此时还使用BufferedReader 
     * 来读时，因为读到最后一行时，最后一行后不会有回车换行符，所以就会等待。如果使用服务器发送回来的 
     * 消息头里的Content-Length来截取消息体，这样就不会阻塞 
     *  
     * contentLe 参数 如果为0时，表示读头，读时我们还是一行一行的返回；如果不为0，表示读消息体， 
     * 时我们根据消息体的长度来读完消息体后，客户端自动关闭流，这样不用先到服务器超时来关闭。 
     */  
    private byte[] readLine(InputStream is, int contentLe) throws IOException { 
    	
//    	 IoBuffer buffer = IoBuffer.allocate(contentLe>0?contentLe:200).setAutoExpand(true);
    	List<Byte> buffer=new ArrayList<Byte>();
    	
        if (contentLe > 0) {
        	int total=0 ; 
            do {  
                buffer.add((byte) is.read());
                total++;  
            } while (total < contentLe);//消息体读还未读完  
            logger.debug("读入数据长度："+buffer.size());
           
        } else {  
        	 byte readByte=0 ;
            do {  
                readByte = (byte) is.read();  
                buffer.add(readByte);
            } while (readByte != 10);  //换行符
        }  
        
        byte[] tmpByteArr = new byte[buffer.size()];  
        for (int i = 0; i < buffer.size(); i++) {  
            tmpByteArr[i] = ((Byte) buffer.get(i)).byteValue();  
        }  
        buffer.clear();  
        
        logger.debug("读入数据："+new String(tmpByteArr,encoding));
       return tmpByteArr;
    }  
    
    @Override
    public void sessionIdle( IoSession session, IdleStatus status ) throws Exception
    {
    	logger.warn( "IDLE " + session.getIdleCount( status ));
    }
}
